
import java.nio.FloatBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import com.jogamp.common.nio.Buffers;


class Renderer implements GLEventListener 
{
    private GLU glu = new GLU();
    private Model model;
    private int myRoomList, myObjectList;
    
    
    private ObjData roomObj = ObjData.getRoom();
    private ObjData mainObj = new ObjData();

    
    public void setModel(Model model){
    	this.model = model;
    }
    
    public void display(GLAutoDrawable gLDrawable) {
    	GL2 gl = gLDrawable.getGL().getGL2();
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
        gl.glEnable(GL2.GL_DEPTH_TEST);
        gl.glLoadIdentity();
        
        glu.gluLookAt(0.0, 0.0, -1.4, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
        
        setLightModel(gl);
        
    	if (model.renderSettings == 0) simpleDisplay(gl);
    	if (model.renderSettings == 1) ListDisplay(gl);
    	//if (model.renderSettings == 2) arrayDisplay(gl);    	
    }
    
    private void setLightModel(GL2 gl){
    	float lmodel_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f}; 
        gl.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, lmodel_ambient,0);
        gl.glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL2.GL_TRUE);       
        gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL2.GL_TRUE);
        
        gl.glEnable(GL2.GL_LIGHTING);
        gl.glEnable(GL2.GL_LIGHT0);
        gl.glDepthFunc(GL2.GL_LEQUAL);
        gl.glEnable(GL2.GL_NORMALIZE);
        
    	if (model.lightSettings == 0) setDirectLight(gl);
    	if (model.lightSettings == 1) setPointLight(gl);
    	if (model.lightSettings == 2) setSpotLight(gl);       

    }
    

    
    private void setDirectLight(GL2 gl){
        float light_specular[] = { 0.9f, 0.9f, 0.9f, 1.0f };
        float light_shininess[] = { 50.0f };
        float light_diffuse[] = { 0.9f, 0.9f, 0.9f, 1.0f };
        float direct_light_position[] = { 0.0f, 5.0f, 0.0f, 0.0f };

        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, direct_light_position,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, light_specular,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SHININESS, light_shininess,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, light_diffuse,0);
        gl.glLightf(GL2.GL_LIGHT0, GL2.GL_SPOT_CUTOFF, 180.0f);
    }
    
    private void setPointLight(GL2 gl){
        float light_specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
        float light_shininess[] = { 50.0f };
        float light_diffuse[] = { 0.6f, 0.6f, 0.6f, 1.0f };
        float point_light_position[] = { 0.0f, 0.38f, 0.0f, 1.0f };

        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, point_light_position,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, light_specular,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SHININESS, light_shininess,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, light_diffuse,0);
        gl.glLightf(GL2.GL_LIGHT0, GL2.GL_SPOT_CUTOFF, 180.0f);
    }
    
    private void setSpotLight(GL2 gl){
        float light_specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
        float light_shininess[] = { 50.0f };
        float light_diffuse[] = { 0.6f, 0.6f, 0.6f, 1.0f };
        float spot_light_position[] = { 0.0f, 0.0f, -0.8f, 1.0f };
        float spot_direction[] = { 0.0f, 0.0f, 1.0f };

        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, spot_light_position,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, light_specular,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SHININESS, light_shininess,0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, light_diffuse,0);
        gl.glLightf(GL2.GL_LIGHT0, GL2.GL_SPOT_CUTOFF, 45.0f);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPOT_DIRECTION, spot_direction,0 );
    }
    
    private void simpleDisplay(GL2 gl){
    	setDrawingModel(gl); 
    	drawObject(gl, roomObj);
        gl.glRotated(model.angle, 0, 1, 0);
        scaleObject(gl);
        drawObject(gl, mainObj);
    	gl.glFlush();
    }
    
    public void ListDisplay(GL2 gl){ 	
        gl.glCallList(myRoomList);
        gl.glRotated(model.angle, 0, 1, 0);
        scaleObject(gl);
        gl.glCallList(myObjectList);
        gl.glFlush();
    }
    
    public void arrayDisplay(GL2 gl){   	
        //gl.glDrawArrays( GL2.GL_TRIANGLES, 0, objData.vertices.size() );
        //gl.glFlush();
    }
             

    public void init(GLAutoDrawable gLDrawable){
    	
    	mainObj.init();
   	
    	GL2 gl = gLDrawable.getGL().getGL2();
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glShadeModel(GL2.GL_FLAT);
        
        //create display lists
        myRoomList = gl.glGenLists(1);
        gl.glNewList(myRoomList, GL2.GL_COMPILE);
        setDrawingModel(gl);
        drawObject(gl, roomObj);
        gl.glEndList();
        
        myObjectList = gl.glGenLists(1);
        gl.glNewList(myObjectList, GL2.GL_COMPILE);
        drawObject(gl, mainObj);
        gl.glEndList();
        
        //create data arrays
        gl.glEnableClientState( GL2.GL_VERTEX_ARRAY );
        gl.glEnableClientState( GL2.GL_NORMAL_ARRAY );
        initArrayData(gl);


    }
 
    private void initArrayData( GL2 gl ){
        FloatBuffer points;
        FloatBuffer normals;
    	float[] tempN, tempV;
    	points = Buffers.newDirectFloatBuffer(mainObj.vertices.size() * 3);
    	normals = Buffers.newDirectFloatBuffer(mainObj.vertices.size() * 3);
        for( int i=0; i < mainObj.vertices.size(); i++ ){
        	tempN = mainObj.normals.get(i);
    		tempV = mainObj.vertices.get(i);   		
        	points.put(tempV[0]);
        	points.put(tempV[1]);
        	points.put(tempV[2]);
        	normals.put(tempN[0]);
        	normals.put(tempN[1]);
        	normals.put(tempN[2]);
        	points.rewind();
        }
    	points.rewind();
    	normals.rewind();
    	gl.glColorPointer( 3, GL.GL_FLOAT, 0, points );
    	gl.glColorPointer( 3, GL.GL_FLOAT, 0, normals );
    }

    public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height){

        final GL2 gl = gLDrawable.getGL().getGL2();
 
        if (height <= 0) // avoid a divide by zero error!
        {
            height = 1;
        }
 
        final float h = (float) width / (float) height;
 
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, h, 0.7, 20.0);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

	private void setDrawingModel(GL2 gl){
    	float mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        float mat_shininess[] = { 50.0f };       
        gl.glEnable(GL2.GL_COLOR_MATERIAL);
        gl.glColorMaterial(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE);
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, mat_specular,0);
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SHININESS, mat_shininess,0);	
	}
	
    private void drawObject(GL2 gl, ObjData obj){
        float[] tempN, tempV;      
    	gl.glBegin(GL2.GL_TRIANGLES);
    	gl.glColor3f(1.0f,0.894f,0.769f);
    	for (int i=0; i<obj.vertices.size(); i++){
    		tempN = obj.normals.get(i);
    		tempV = obj.vertices.get(i);
    		gl.glNormal3f(tempN[0], tempN[1], tempN[2]);
    		gl.glVertex3f(tempV[0], tempV[1], tempV[2]);
    	}
    	gl.glEnd();
    }
    
    public static void scaleObject(GL2 gl){
    	double lowx = Double.MAX_VALUE;
    	double lowy = Double.MAX_VALUE;
    	double lowz = Double.MAX_VALUE;
    	
    	double highx = Double.MIN_VALUE;
    	double highy = Double.MIN_VALUE;
    	double highz = Double.MIN_VALUE;
    	
    	double diffx, diffy, diffz;
   	
    	for (int i=1; i< verts.vertexes.length; i++){
    		if (verts.vertexes[i][0] < lowx) lowx = verts.vertexes[i][0];
    		if (verts.vertexes[i][1] < lowy) lowy = verts.vertexes[i][1];
    		if (verts.vertexes[i][2] < lowz) lowz = verts.vertexes[i][2];

    		if (verts.vertexes[i][0] > highx) highx = verts.vertexes[i][0];
    		if (verts.vertexes[i][1] > highy) highy = verts.vertexes[i][1];
    		if (verts.vertexes[i][2] > highz) highz = verts.vertexes[i][2];

    	}
    	
    	diffx = highx - lowx;
    	diffy = highy - lowy;
    	diffz = highz - lowz;

    	gl.glScaled(0.4/diffx, 0.4/diffy, 0.4/diffz);
    	gl.glTranslated((diffx/2) - highx, (diffy/2) - highy, (diffz/2) - highz);
    }
    
	public void dispose(GLAutoDrawable arg0){}
}

/*
private void drawRoom(GL2 gl){        
float[][] points = { {0,0,0},
		{0.4f,0.4f,0.4f} ,	{-0.4f,0.4f,0.4f} ,	{0.4f,0.4f,0.1f} ,	{0.1f,0.4f,0.1f} ,
		{-0.1f,0.4f,0.1f} ,	{-0.4f,0.4f,0.1f} ,	{0.1f,0.4f,-0.1f} ,	{-0.1f,0.4f,-0.1f} ,
		{0.4f,0.4f,-0.8f} ,	{0.1f,0.4f,-0.8f} ,	{-0.1f,0.4f,-0.8f} ,	{-0.4f,0.4f,-0.8f} ,
		{0.4f,-0.4f,0.4f} ,	{0.4f,-0.4f,-0.8f} ,	{-0.4f,-0.4f,-0.8f} ,	{-0.4f,-0.4f,0.4f} ,
};

gl.glBegin(GL2.GL_TRIANGLES);
gl.glColor3f(1.0f,0.894f,0.769f);

//ceiling
gl.glNormal3d(0.0, -1.0, 0.0);
gl.glVertex3f(points[1][0],points[1][1], points[1][2]);gl.glVertex3f(points[3][0],points[3][1], points[3][2]);gl.glVertex3f(points[2][0],points[2][1], points[2][2]);	
gl.glVertex3f(points[3][0],points[3][1], points[3][2]);gl.glVertex3f(points[6][0],points[6][1], points[6][2]);gl.glVertex3f(points[2][0],points[2][1], points[2][2]);
gl.glVertex3f(points[3][0],points[3][1], points[3][2]);gl.glVertex3f(points[9][0],points[9][1], points[9][2]);gl.glVertex3f(points[4][0],points[4][1], points[4][2]);
gl.glVertex3f(points[9][0],points[9][1], points[9][2]);gl.glVertex3f(points[10][0],points[10][1], points[10][2]);gl.glVertex3f(points[4][0],points[4][1], points[4][2]);
gl.glVertex3f(points[7][0],points[7][1], points[7][2]);gl.glVertex3f(points[10][0],points[10][1], points[10][2]);gl.glVertex3f(points[8][0],points[8][1], points[8][2]);
gl.glVertex3f(points[8][0],points[8][1], points[8][2]);gl.glVertex3f(points[10][0],points[10][1], points[10][2]);gl.glVertex3f(points[11][0],points[11][1], points[11][2]);
gl.glVertex3f(points[11][0],points[11][1], points[11][2]);gl.glVertex3f(points[12][0],points[12][1], points[12][2]);gl.glVertex3f(points[5][0],points[5][1], points[5][2]);
gl.glVertex3f(points[5][0],points[5][1], points[5][2]);gl.glVertex3f(points[12][0],points[12][1], points[12][2]);gl.glVertex3f(points[6][0],points[6][1], points[6][2]);

//back wall
gl.glNormal3d(0.0, 0.0, -1.0);
gl.glVertex3f(points[2][0],points[2][1], points[2][2]);gl.glVertex3f(points[1][0],points[1][1], points[1][2]);gl.glVertex3f(points[16][0],points[16][1], points[16][2]);
gl.glVertex3f(points[1][0],points[1][1], points[1][2]);gl.glVertex3f(points[13][0],points[13][1], points[13][2]);gl.glVertex3f(points[16][0],points[16][1], points[16][2]);

//front wall
gl.glNormal3d(0.0, 0.0, -1.0);
gl.glVertex3f(points[9][0],points[9][1], points[9][2]);gl.glVertex3f(points[14][0],points[14][1], points[14][2]);gl.glVertex3f(points[15][0],points[15][1], points[15][2]);
gl.glVertex3f(points[12][0],points[12][1], points[12][2]);gl.glVertex3f(points[9][0],points[9][1], points[9][2]);gl.glVertex3f(points[15][0],points[15][1], points[15][2]);

//floor
gl.glNormal3d(0.0, 1.0, 0.0);
gl.glVertex3f(points[16][0],points[16][1], points[16][2]);gl.glVertex3f(points[13][0],points[13][1], points[13][2]);gl.glVertex3f(points[15][0],points[15][1], points[15][2]);
gl.glVertex3f(points[13][0],points[13][1], points[13][2]);gl.glVertex3f(points[14][0],points[14][1], points[14][2]);gl.glVertex3f(points[15][0],points[15][1], points[15][2]);

//left wall
gl.glNormal3d(1.0, 0.0, 0.0);
gl.glColor3f(0.45f,0.1f,0.05f);
gl.glVertex3f(points[1][0],points[1][1], points[1][2]);gl.glVertex3f(points[13][0],points[13][1], points[13][2]);gl.glVertex3f(points[9][0],points[9][1], points[9][2]);
gl.glVertex3f(points[13][0],points[13][1], points[13][2]);gl.glVertex3f(points[14][0],points[14][1], points[14][2]);gl.glVertex3f(points[9][0],points[9][1], points[9][2]);

//right wall
gl.glNormal3d(1.0, 0.0, 0.0);
gl.glColor3f(0.1f,0.45f,0.05f);
gl.glVertex3f(points[2][0],points[2][1], points[2][2]);gl.glVertex3f(points[16][0],points[16][1], points[16][2]);gl.glVertex3f(points[12][0],points[12][1], points[12][2]);
gl.glVertex3f(points[12][0],points[12][1], points[12][2]);gl.glVertex3f(points[16][0],points[16][1], points[16][2]);gl.glVertex3f(points[15][0],points[15][1], points[15][2]);

gl.glEnd();

}*/